home *** CD-ROM | disk | FTP | other *** search
- ; Wb-tree File Based Associative String Data Base System.
- ; Copyright (c) 1991, 1992, 1993 Holland Mark Martin
- ;
- ;Permission to use, copy, modify, and distribute this software and its
- ;documentation for educational, research, and non-profit purposes and
- ;without fee is hereby granted, provided that the above copyright
- ;notice appear in all copies and that both that copyright notice and
- ;this permission notice appear in supporting documentation, and that
- ;the name of Holland Mark Martin not be used in advertising or
- ;publicity pertaining to distribution of the software without specific,
- ;written prior consent in each case. Permission to incorporate this
- ;software into commercial products can be obtained from Jonathan
- ;Finger, Holland Mark Martin, 174 Middlesex Turnpike, Burlington, MA,
- ;01803-4467, USA. Holland Mark Martin makes no representations about
- ;the suitability or correctness of this software for any purpose. It
- ;is provided "as is" without express or implied warranty. Holland Mark
- ;Martin is under no obligation to provide any services, by way of
- ;maintenance, update, or otherwise.
-
- (require (in-vicinity (program-vicinity) "sys"))
-
- ;;;; tables
-
- (define lck-tab #f)
- (define buk-tab #f)
- (define ent-tab #f)
- (define num-ents-ct 0)
- (define num-buks 0)
- (define blk-size 0)
- (define empty-blk #f)
- (define empty-blk-lck #f)
-
- (define cache-ent-enable #t)
-
- ;;;; DATABASE LEVEL OPERATIONS
-
- ;;; This can be bummed to write less than the full BSIZ if we know
- ;;; what the disk sector size is.
- ;; fixed order check in ent-write
-
- (define (ent-write ent)
- (define seg (ENT-SEG ent))
- (define blk (ENT-BLK ent))
- ;; (fprintf diagout "Writing block %d:%ld\\n" seg (ENT-ID ent))
- (if (not (BLK-TYP? blk SEQ-TYP))
- (check-key-order! blk))
- (BLK-SET-TIME! blk (get-universal-time))
- (cond ((= -2 (SEG-FLC-LEN seg))
- (fprintf diagout
- ">>>>ERROR<<<< ent-write on read only segment %d?\\n" seg)
- #f)
- ((blk-write (SEG-PORT seg) (ENT-BLK ent) (SEG-BSIZ seg) (ENT-ID ent))
- (ENT-SET-DTY! ent #f)
- #t)
- (else
- (ENT-SET-DTY! ent #t)
- #f)))
-
- ;;; FLUSHING needs to be proportional to time (to put some limit on how long
- ;;; things are left unwritten) plus write-activity.
- ;;; NOTE: While flushing a buffer, get accpend access to it (to prevent surprise mods)
- ;;; 3/93 if maxnum argument is 0, will return nonzero if there are
- ;;; entries to be flushed within numbuks buckets.
- (define flush-buk-cntr #f)
- (define flush-buk-lck #f)
-
- (define (flush-some-buks numbuks maxnum)
- (define numflushed 0)
- (and
- (try-lck flush-buk-lck)
- (do ((i numbuks (- i 1)))
- ((or (zero? i) (> numflushed maxnum))
- (if (zero? maxnum)
- (set! flush-buk-cntr (remainder (+ -1 flush-buk-cntr) num-buks)))
- (unlck! flush-buk-lck)
- numflushed)
- (set! flush-buk-cntr (remainder (+ 1 flush-buk-cntr) num-buks))
- (and (GET-BUK-LCK 0 flush-buk-cntr)
- (do ((ent (GET-BUK 0 flush-buk-cntr) (ENT-NEXT ent)))
- ((not ent) (REL-BUK! 0 flush-buk-cntr))
- (if (and (ENT-DTY? ent) (not (ENT-ACC ent)))
- ;;TBD- when multiple readers are allowed we can use
- ;;read access instead of accpend access to exclude writers.
- ;;trust me. you need this.
- (cond ((not (zero? maxnum))
- (ENT-SET-ACC! ent accpend)
- (REL-BUK! 0 flush-buk-cntr)
- (ent-write ent)
- (GET-BUK-WAIT 0 flush-buk-cntr)
- (ENT-SET-ACC! ent #f)
- (set! flush-ct (+ flush-ct 1))))
- (set! numflushed (+ numflushed 1))))))))
-
- ;;; release-ent! gives up all claim to ent, which is expected to be of
- ;;; type acctype
- ;; fixed warning about dirty dirs -- twice
- ;; fixed dirty-block writer in UPDATE-ACCESS!
-
- (define (release-ent! ent acctype)
- (define blknum (ENT-ID ent))
- (define seg (ENT-SEG ent))
- (define buk #f)
- ;;; (fprintf diagout "release-ent! %d:%ld %d\\n" seg blknum acctype)
- (set! buk (GET-BUK-WAIT seg blknum))
- ;;;(if (not (BLK-TYP? (ENT-BLK ent) SEQ-TYP))
- ;;; (check-key-order! (ENT-BLK ent)))
- (if (and acctype (not (eq? (ENT-ACC ent) acctype)))
- ;;TBD- clean this error up
- (fprintf
- diagout
- ">>>>ERROR<<<< RELEASE-ENT!: unexpected acctype of %d:%ld is %d not %d\\n"
- seg blknum (ENT-ACC ent) acctype))
- (cond ((not acctype))
- ((not (ENT-DTY? ent)))
- ((BLK-TYP? (ENT-BLK ent) DIR-TYP)
- (fprintf diagout ">>>>WARNING<<<< Directory block %d:%ld dirty at RELEASE-ENT! \\n" seg blknum)
- (set! dir-dty-ct (+ 1 dir-dty-ct)))
- ((BLK-TYP? (ENT-BLK ent) SEQ-TYP)
- (REL-BUK! seg blknum)
- (ent-write ent)
- (set! buk (GET-BUK-WAIT seg blknum))))
- (if acctype (ENT-SET-ACC! ent #f))
- (cond ((<= (ENT-REF ent) 0)
- (ENT-SET-REF! ent 0)
- (fprintf diagout ">>>>ERROR<<<< REF count below 0 in %d:%ld\\n"
- seg blknum))
- (else
- (ENT-SET-REF! ent (- (ENT-REF ent) 1))))
- (cond ((negative? seg)
- (splice-out-ent! seg blknum buk ent))
- (else
- (ENT-SET-AGE! ent (+ (if (ENT-DTY? ent) 5 0)
- (* 5 (+ 6 (- LEAF (BLK-LEVEL (ENT-BLK ent)))))))))
- (REL-BUK! seg blknum))
-
- (define (ent-update-access ent old-acctype new-acctype)
- ; (fprintf diagout "ent-update-access %d:%ld %d %d\\n"
- ; (ENT-SEG ent) (ENT-ID ent) old-acctype new-acctype)
- (GET-BUK-WAIT (ENT-SEG ent) (ENT-ID ent))
- (cond ((not (eq? (ENT-ACC ent) old-acctype))
- (REL-BUK! (ENT-SEG ent) (ENT-ID ent))
- (fprintf diagout ">>>>ERROR<<<< unexpected access type on %d:%ld %d\\n"
- (ENT-SEG ent) (ENT-ID ent) (ENT-ACC ent))))
- (cond ((not old-acctype))
- ((not (ENT-DTY? ent)))
- ((BLK-TYP? (ENT-BLK ent) SEQ-TYP)
- (REL-BUK! (ENT-SEG ent) (ENT-ID ent))
- (ent-write ent)
- (GET-BUK-WAIT (ENT-SEG ent) (ENT-ID ent)))
- ((BLK-TYP? (ENT-BLK ent) DIR-TYP)
- (fprintf diagout ">>>>WARNING<<<< Directory block %d:%ld dirty at ENT-UPD-ACCESS! \\n" (ENT-SEG ent) (ENT-ID ent))
- (set! dir-dty-ct (+ 1 dir-dty-ct)))
- )
- (ENT-SET-ACC! ent new-acctype)
- (REL-BUK! (ENT-SEG ent) (ENT-ID ent))
- (and ent #t))
-
- ;;; ENT-FREE-LIST stuff -----------------------------------------------------------
-
- (define free-buk-cntr #f)
- (define free-ent-lck #f)
- (define free-ents #f)
-
- (define (get-free-free-ent)
- (lck! free-ent-lck)
- (and free-ents
- (let ((free-ent free-ents))
- (set! free-ents (ENT-NEXT free-ents))
- (unlck! free-ent-lck)
- free-ent)))
-
- ;; this version assumes the caller has already locked the bucket
- ;; BUK containing ENT
-
- (define (splice-out-ent! seg blk-num buk ent)
- (do ((bent buk (ENT-NEXT bent))
- (lastent #f bent))
- ((or (not bent) (eq? bent ent))
- (cond
- (bent (if lastent
- (ENT-SET-NEXT! lastent (ENT-NEXT bent))
- (SET-BUK! seg blk-num (ENT-NEXT bent)))
- ;;; (fprintf diagout "SPLICING OUT buk=%d:%ld ent=%d:%ld last=%d\\n"
- ;;; seg blk-num (ENT-SEG bent) (ENT-ID bent)
- ;;; (if lastent (ENT-ID lastent) -1))
- (recycle-ent! bent))
- (else (fprintf diagout ">>>>WARNING<<<< couldn't splice-out-ent! %d:%ld\\n"
- seg blk-num))))))
-
- (define (recycle-ent! ent)
- (ENT-SET-DTY! ent #f)
- (ENT-SET-PUS! ent 0)
- (ENT-SET-SEG! ent -1)
- (ENT-SET-ID! ent -1)
- (lck! free-ent-lck)
- (ENT-SET-REF! ent 0)
- (ENT-SET-ACC! ent #f)
- (ENT-SET-NEXT! ent free-ents)
- (set! free-ents ent)
- (unlck! free-ent-lck))
-
- ;;; SELECT-IDLE-ENT selects a candidate entry for reuse. caller needs to call
- ;;; RECLAIM-ENT next to splice entry out of its bucket.
- ;;; NOTE: when called, bucket (lseg lblk-num) is lcked.
- ;;; The target bucket is assumed unlocked if lseg < 0.
- ;;; (GET-ENT calls this with the bucket locked to prevent someone else from
- ;;; getting another entry for the same block.)
-
- (define (select-idle-ent lseg lblk-num)
- ;;; (fprintf diagout "select-idle-ent %d:%ld\\n" lseg lblk-num)
- (let ((oldest-ent #f)
- (num-scan (max (min num-buks 10) (quotient num-buks 20)))
- (free-base free-buk-cntr))
- ;;; (fprintf diagout "select-idle-ent: aging %d buks\\n" num-scan)
- (set! free-buk-cntr (remainder (+ num-scan free-buk-cntr) num-buks))
- (unlck! free-ent-lck)
- (do ((i 0 (+ i 1)))
- ((or (and (> i num-scan) oldest-ent) (> i num-buks))
- ;;; This searches num-buks/20 buckets, or some minimum number like 10.
- ;;; (fprintf diagout "reclaiming ent= %d:%ld age=%d\\n"
- ;;; (if oldest-ent (ENT-SEG oldest-ent) -1)
- ;;; (if oldest-ent (ENT-ID oldest-ent) -1)
- ;;; (if oldest-ent (ENT-AGE oldest-ent) -999))
- (if (> i num-buks)
- (fprintf diagout ">>>>ERROR<<<< No free ents\\n"))
- oldest-ent)
- (let* ((free-num (remainder (+ free-base i) num-buks))
- (dont-lock? (if (negative? lseg) #f
- (= free-num (HASH2INT lseg lblk-num)))))
- (and
- (or dont-lock? (GET-BUK-LCK 0 free-num))
- (do ((ent (GET-BUK 0 free-num) (ENT-NEXT ent)))
- ((not ent) (or dont-lock? (REL-BUK! 0 free-num)))
- ;;; (fprintf diagout "select-idle-ent i= %d oldest-ent= %d:%ld ent= %d:%ld\\n"
- ;;; i (if oldest-ent (ENT-SEG oldest-ent) 0)
- ;;; (if oldest-ent (ENT-ID oldest-ent) -1)
- ;;; (ENT-SEG ent) (ENT-ID ent))
- (if (zero? (ENT-REF ent))
- (begin
- (ENT-SET-AGE! ent (+ (if (ENT-DTY? ent) 1 2) (ENT-AGE ent)))
- (and (not (ENT-ACC ent)) ;this is redundant but robust
- (or (not oldest-ent) (> (ENT-AGE ent) (ENT-AGE oldest-ent)))
- (set! oldest-ent ent))))))))))
-
- ;;; RECLAIM-ENT unlinks ENT from its bucket if its not in use.
- ;;; It writes out the entry-s block if it's dirty
- ;;; RECLAIM-ENT has 3 cases
- ;;; (a) ENT is in use -- LSEG is unlocked, NIL is returned
- ;;; (b) ENT is clean -- ENT is unlinked and returned
- ;;; (c) ENT is DIRTY -- ENT is written, unlinked, and reclaimed (put on
- ;;; free lsit); LSEG is UNLOCKED, NIL is returned.
- ;;; possible optimization in case (c): if LSEG = -,
- ;;; ENT could be written, unlinked, and returned (like (b))
-
- (define (reclaim-ent ent lseg lblk-num)
- (let* ((seg (ENT-SEG ent))
- (blk-num (ENT-ID ent))
- (segs-equal? (and (not (negative? lseg))
- (SAME-BUK? lseg lblk-num seg blk-num)))
- (buk (if segs-equal?
- (GET-BUK seg blk-num)
- (GET-BUK-WAIT seg blk-num))))
- (cond ((or (not (zero? (ENT-REF ent))) ; ENT in use?
- (ENT-ACC ent))
- (REL-BUK! seg blk-num)
- (or segs-equal? (negative? lseg) (REL-BUK! lseg lblk-num))
- (fprintf diagout ">>>>WARNING<<<< reclaim-ent: couldn't splice-out-ent %d:%ld\\n"
- lseg lblk-num)
- #f)
- (else
- (do ((bent buk (ENT-NEXT bent))
- (lastent #f bent))
- ((or (not bent) (eq? ent bent))
- (cond
- ((not bent)
- (REL-BUK! seg blk-num)
- (or segs-equal? (negative? lseg) (REL-BUK! lseg lblk-num))
- (fprintf diagout ">>>>ERROR<<<< reclaim-ent: couldn't find ent in bucket %d:%ld l=%d:%ld\\n"
- seg blk-num lseg lblk-num)
- #f)
- ;;ent and bent are now the same
- ((not (ENT-DTY? ent))
- (if lastent ; unlink
- (ENT-SET-NEXT! lastent (ENT-NEXT ent))
- (SET-BUK! seg blk-num (ENT-NEXT ent)))
- (ENT-SET-NEXT! ent #f) ;for safety
- (or segs-equal? (REL-BUK! seg blk-num))
- ;;; (fprintf diagout "reclaim-ent CLEAN: ent= %d:%ld l=%d:%ld seq=%d\\n"
- ;;; seg blk-num lseg lblk-num (if segs-equal? 1 0))
- ent)
- (else ;ent is DTY
- (ENT-SET-ACC! ent accpend)
- (REL-BUK! seg blk-num)
- (or segs-equal? (negative? lseg) (REL-BUK! lseg lblk-num))
- (ent-write ent)
- (set! buk (GET-BUK-WAIT seg blk-num))
- (ENT-SET-ACC! ent #f)
- ; if (negative? lseg) then should return it directly
- (splice-out-ent! seg blk-num buk ent)
- (REL-BUK! seg blk-num)
- ;;; (fprintf diagout "reclaim-ent DIRTY: ent= %d:%ld l=%d:%ld seq=%d\\n"
- ;;; seg blk-num lseg lblk-num (if segs-equal? 1 0))
- #f)))))
- )))
-
- ;; TRY-GET-FREE-ENT either returns a free ent OR unlocks (lseg lblk-num)
-
- (define (try-get-free-ent lseg lblk-num)
- (define ent (get-free-free-ent))
- (cond ((not ent)
- (set! ent (select-idle-ent lseg lblk-num))
- (if ent (set! ent (reclaim-ent ent lseg lblk-num))
- (or (negative? lseg) (REL-BUK! lseg lblk-num)))))
- ent)
-
-
- ;;; Special entry points for Jonathan to do non-B-tree stuff.
- ;;; Also now used in chain-scan.
-
- (define (allocate-ent)
- (define ent (try-get-free-ent -1 -1))
- (cond (ent
- (ENT-SET-ACC! ent ACCWRITE)
- (ENT-SET-DTY! ent #t)
- (ENT-SET-PUS! ent 0)
- (ENT-SET-SEG! ent -1)
- (ENT-SET-ID! ent -1)
- (ENT-SET-REF! ent 1)
- (ENT-SET-NEXT! ent #f)
- ent)
- (else
- (allocate-ent))))
-
- (define (ent-copy! to-ent from-ent)
- (if (not (eq? (ENT-ACC to-ent) ACCWRITE))
- (fprintf diagout ">>>>ERROR<<<< ent-copy!: copying into non-ACCWRITE %d:%d\\n"
- (ENT-SEG to-ent) (ENT-ID to-ent)))
- (ENT-SET-SEG! to-ent (ENT-SEG from-ent))
- (ENT-SET-ID! to-ent (ENT-ID from-ent))
- (substring-move! (ENT-BLK from-ent) 0 (SEG-BSIZ (ENT-SEG from-ent)) (ENT-BLK to-ent) 0))
-
- (define (get-ent-copy to-ent seg blk-num)
- (define from-ent (get-ent seg blk-num ACCREAD))
- (cond (from-ent
- (ent-copy! to-ent from-ent)
- (release-ent! from-ent ACCREAD)
- #t)
- (else #f)))
-
- (define (write-ent-copy ent)
- (define to-ent (get-ent (ent-seg ent) (ent-id ent) ACCWRITE))
- (cond (to-ent
- (ent-copy! to-ent ent)
- (ENT-SET-DTY! to-ent #t)
- (release-ent! to-ent ACCWRITE)
- #t)
- (else #f)))
-
- ;;; End of Special entry points for Jonathan to do non-B-tree stuff.
-
- ;;;; Stuff to deal with the free-list-cache (FLC)
-
- (define (flush-flc! seg fullness)
- (define fstr (make-string 4))
- (define tstr (make-string 4))
- (lck! (SEG-LCK seg))
- (cond ((<= (SEG-FLC-LEN seg) fullness)
- (unlck! (SEG-LCK seg)))
- (else
- (long2str! fstr 0 (vector-ref (SEG-FLC seg) (- (SEG-FLC-LEN seg) 1)))
- (SEG-SET-FLC-LEN! seg (- (SEG-FLC-LEN seg) 1))
- (unlck! (SEG-LCK seg))
- ;;;#|f|# (fprintf diagout "flush-flc! %d:%d\\n" seg (str2long fstr 0))
- (long2str! tstr 0 (get-universal-time))
- (bt-put (SEG-FL-HAN seg) fstr 4 tstr 4) ;TBD check for error
- (flush-flc! seg fullness))))
-
- ;;; Assumes that SEG-LCK is locked by this process
-
- (define (initload-flc? seg)
- (case (SEG-FLC-LEN seg)
- ((-1) (let* ((tmp-str (make-string 20))
- (flc-image-len (bt-get (SEG-RT-HAN seg) "FLC" 3 tmp-str)))
- (if (negative? flc-image-len) (set! flc-image-len 0)) ;TBD ??
- (bt-put (SEG-RT-HAN seg) "FLC" 3 "" 0)
- (SEG-SET-FLC-LEN! seg (quotient flc-image-len 4))
- (do ((i (+ -4 flc-image-len) (+ -4 i)))
- ((negative? i))
- ;;; (fprintf diagout "%d %ld\n" i (str2long tmp-str i))
- (vector-set! (SEG-FLC seg) (quotient i 4) (str2long tmp-str i))))
- #t)
- ((-2) (fprintf diagout
- ">>>>ERROR<<<< initload-flc! on read only segment %d?\\n" seg)
- #f)
- (else #t)))
-
- (define (blk-free ent)
- (define seg (ENT-SEG ent))
- ;;;#|f|# (fprintf diagout "blk-free %d:%d\\n" seg (ENT-ID ent))
- (cond ((not (eq? (ENT-ACC ent) ACCWRITE))
- (fprintf diagout ">>>>ERROR<<<<blk-free: %d:%ld without ACCWRITE\\n"
- (ENT-SEG ent) (ENT-ID ent))
- #f)
- (else
- (lck! (SEG-LCK seg))
- (cond
- ((not (initload-flc? seg)) (unlck! (SEG-LCK seg)) #f)
- ((>= (SEG-FLC-LEN seg) (- FLC-LEN 1))
- (unlck! (SEG-LCK seg))
- (flush-flc! seg (- FLC-LEN 2))
- (blk-free ent))
- (else
- (vector-set! (SEG-FLC seg) (SEG-FLC-LEN seg) (ENT-ID ent))
- (SEG-SET-FLC-LEN! seg (+ (SEG-FLC-LEN seg) 1))
- (amnesia-ent! ent) ;renumber entry to seg -1
- (unlck! (SEG-LCK seg))
- #t)))))
-
- (define (flc-fill seg)
- (define fstr (make-string 4))
- (define flen #f)
- ;;;#|f|# (fprintf diagout "flc-fill %d\\n" (SEG-FLC-LEN seg))
- (lck! (SEG-LCK seg))
- (cond ((>= (SEG-FLC-LEN seg) 1)
- (unlck! (SEG-LCK seg)) SUCCESS) ;FLC has some blks in it.
- ((not (try-lck (SEG-FCK seg))) ; prevent multiple fillers
- (unlck! (SEG-LCK seg))
- (fprintf diagout
- ">>>>WARNING<<<< Failed to get FLCK-- branch never tried before! Segment %d %s\\n"
- seg (SEG-STR seg))
- RETRYERR)
- ((begin
- (set! flen (bt-next (SEG-FL-HAN seg) "" 0 fstr))
- (err? flen)) ;No blks left in free-list
- (lck! empty-blk-lck)
- (let ((xnum (+ (SEG-USED seg) (quotient FLC-LEN 2))))
- (init-leaf-blk! empty-blk xnum IND-TYP)
- (cond ((extend-file (SEG-PORT seg) empty-blk (SEG-BSIZ seg) xnum)
- (if io-diag
- (fprintf diagout
- ">>>>EXTENDING<<<< Segment %d %s by %d blocks.\\n"
- seg (SEG-STR seg) (quotient FLC-LEN 2)))
- (do ((i 0 (+ i 1)))
- ((> i (quotient FLC-LEN 2))) ;this is actually + 1.
- (vector-set! (SEG-FLC seg) (SEG-FLC-LEN seg) (- xnum i))
- ;;reverse order so blks are allocated in order
- (SEG-SET-FLC-LEN! seg (+ (SEG-FLC-LEN seg) 1))
- (SEG-SET-USED! seg (+ (SEG-USED seg) 1)))
- (let ((used-str (make-string 4))) ; This put should not cause a split!
- (long2str! used-str 0 (SEG-USED seg))
- (bt-put (SEG-RT-HAN seg) "USED" 4 used-str 4))
- (unlck! empty-blk-lck)
- (unlck! (SEG-LCK seg))
- (unlck! (SEG-FCK seg))
- SUCCESS)
- (else
- (fprintf diagout
- ">>>>ERROR<<<< No more file space available! Segment %d %s\\n"
- seg (SEG-STR seg))
- (unlck! empty-blk-lck)
- (unlck! (SEG-LCK seg))
- (unlck! (SEG-FCK seg))
- NOROOM))))
- (else
- (unlck! (SEG-LCK seg))
- (let ((long-ara (make-vector (+ FLC-LEN 1)))
- (xstr (make-string 256))
- (respkt (make-vector PKT-SIZE))
- (result SUCCESS))
- (substring-move! fstr 0 flen xstr 0)
- (vector-set! long-ara 0 0) ; data count
- (SET-SKEY-COUNT! respkt 0)
- (set! result (bt-scan (SEG-FL-HAN seg) REM-SCAN xstr flen
- "" END-OF-CHAIN flc-proc long-ara respkt 1))
- (cond ((or (= result SUCCESS) (= result NOTPRES) (= result TERMINATED))
- ;;;#|f|# (fprintf diagout "FLC-FILL: %d blks fetched from free list \\n" (vector-ref long-ara 0))
- (lck! (SEG-LCK seg)) ;successful remove from free-list
- (do ((i (vector-ref long-ara 0) (- i 1)))
- ((<= i 0))
- (vector-set! (SEG-FLC seg) (SEG-FLC-LEN seg)
- (vector-ref long-ara i))
- ;;; (fprintf diagout "FLC-FILL: put block %d into FLC \\n" (vector-ref long-ara i))
- (SEG-SET-FLC-LEN! seg (+ (SEG-FLC-LEN seg) 1)))
- (unlck! (SEG-LCK seg))
- (unlck! (SEG-FCK seg))
- SUCCESS)
- (else
- (unlck! (SEG-FCK seg))
- result))))))
-
- (define (flc-proc keystr klen vstr vlen long-ara)
- (let ((ct (vector-ref long-ara 0)))
- (if (< ct (quotient FLC-LEN 2))
- (let ((num (str2long keystr 0)))
- (set! ct (+ ct 1))
- ;;; (fprintf diagout "FLC-PROC: got block %d ct=%d from freelist \\n" num ct)
- (vector-set! long-ara 0 ct)
- (vector-set! long-ara ct num)
- SUCCESS)
- TERMINATED)))
-
- ;;;create-new-blk-ent leaves you with write access to blk
- (define (create-new-blk-ent seg)
- ;;;#|f|# (fprintf diagout "create-new-blk-ent\\n")
- (lck! (SEG-LCK seg))
- (cond ((not (initload-flc? seg)) (unlck! (SEG-LCK seg)) #f)
- ((<= (SEG-FLC-LEN seg) 0)
- (unlck! (SEG-LCK seg))
- (let ((res (flc-fill seg)))
- (cond ((realerr? res) #f)
- (else (create-new-blk-ent seg)))))
- (else
- (SEG-SET-FLC-LEN! seg (- (SEG-FLC-LEN seg) 1))
- (let ((bnum (vector-ref (SEG-FLC seg) (SEG-FLC-LEN seg))))
- (unlck! (SEG-LCK seg))
- (get-ent seg bnum ACCWRITE))))) ;no read is done here.
- ;;; End of stuff to deal with the free-list-cache (FLC)
-
- ;;; try-get-ent returns an entry with access or #f if blk is lcked. When
- ;;; you are done with the entry you need to release-ent!.
- (define (try-get-ent seg blk-num acctype)
- ;;; (fprintf diagout "try-get-ent %d:%ld %d\\n" seg blk-num acctype)
- (let ((buk (GET-BUK-WAIT seg blk-num)))
- (let entloop ((ent buk))
- (cond
- ((not ent)
- (REL-BUK! seg blk-num)
- (set! tge-fct (+ 1 tge-fct))
- #f)
- ((not (and (= seg (ENT-SEG ent)) (= blk-num (ENT-ID ent)))) ;chain through buk
- (entloop (ENT-NEXT ent)))
- ((not (= (BLK-ID (ENT-BLK ent)) blk-num))
- (REL-BUK! seg blk-num)
- (fprintf diagout ">>>>ERROR<<<< corrupted buffer %d:%ld <> %ld\\n"
- (ENT-SEG ent) (BLK-ID (ENT-BLK ent)) blk-num)
- (set! tge-fct (+ 1 tge-fct))
- #f)
- ((not acctype) ; only asking NAME access
- (ENT-SET-REF! ent (+ 1 (ENT-REF ent)))
- (REL-BUK! seg blk-num)
- (set! tge-ct (+ 1 tge-ct))
- ent)
- ((not (ENT-ACC ent)) ; entry not lcked
- (ENT-SET-ACC! ent acctype)
- ;;; (if (eq? acctype ACCWRITE) (ENT-SET-DTY! ent #t))
- (ENT-SET-REF! ent (+ 1 (ENT-REF ent)))
- (REL-BUK! seg blk-num)
- (set! tge-ct (+ 1 tge-ct))
- ent)
- (else ; entry not available
- (REL-BUK! seg blk-num)
- (set! tge-fct (+ 1 tge-fct))
- #f)))))
-
- (define (chain-find-ent han acctype key-str k-len pkt)
- (define ent
- (if (and cache-ent-enable (HAN-LAST han))
- (try-get-ent (HAN-SEG han) (HAN-LAST han) acctype)
- #f))
- (if (and ent
- (LEAF? (ENT-BLK ent))
- (= (BLK-TOP-ID (ENT-BLK ent)) (HAN-ID han))
- (blk-find-pos (ENT-BLK ent) key-str k-len pkt)
- (or (eq? (MATCH-TYPE pkt) MATCH)
- (and (or (eq? (MATCH-TYPE pkt) PASTP)
- (eq? (MATCH-TYPE pkt) QPASTP))
- (> (MATCH-POS pkt) BLK-DATA-START))))
- (begin
- ;;; (fprintf diagout "chain-find-ent: returned blk %d:%ld\\n" (ENT-SEG ent) (ENT-ID ent))
- (set! tce-ct (+ tce-ct 1))
- ent)
- (begin
- (if ent (release-ent! ent acctype))
- (set! tce-fct (+ tce-fct 1))
- (set! ent (get-ent (HAN-SEG han) (HAN-ID han) #f))
- (cond ((or (not (root? (ENT-BLK ent))) (BLK-TYP? (ENT-BLK ent) SEQ-TYP))
- (fprintf diagout ">>>>ERROR<<<<BT-OPEN: not a B-tree root %d:%d\\n"
- (ENT-SEG ent) (ENT-ID ent))
- (release-ent! ent #f)
- (set! ent #f))
- (else
- (set! ent (find-ent ent LEAF -1 key-str k-len))))
- (cond ((not ent) #f)
- ((eq? acctype ACCREAD) #f)
- ((ent-update-access ent ACCREAD acctype))
- (else (release-ent! ent ACCREAD)
- (set! ent #f)))
- (if ent (set! ent (chain-find ent acctype key-str k-len pkt)))
- (and ent (HAN-SET-LAST! han (ENT-ID ent)))
- ent)))
-
- ; I havent put the call to PREV-K-ENT inside here,
- ; as both paths need to call it - rjz
-
- (define (chain-find-prev-ent han acctype key-str k-len pkt)
- (define ent
- (if (and cache-ent-enable (HAN-LAST han))
- (try-get-ent (HAN-SEG han) (HAN-LAST han) acctype)
- #f))
- (if (and ent
- (LEAF? (ENT-BLK ent))
- (= (BLK-TOP-ID (ENT-BLK ent)) (HAN-ID han))
- (blk-find-pos (ENT-BLK ent) key-str k-len pkt)
- (or (eq? (MATCH-TYPE pkt) MATCH)
- (eq? (MATCH-TYPE pkt) MATCHEND)
- (and (or (eq? (MATCH-TYPE pkt) PASTP)
- (eq? (MATCH-TYPE pkt) QPASTP))
- (> (MATCH-POS pkt) BLK-DATA-START))))
- (begin
- ;;; (fprintf diagout "chain-find-prev-ent: returned blk %d:%ld\\n" (ENT-SEG ent) (ENT-ID ent))
- (set! tce-ct (+ tce-ct 1))
- ent)
- (begin
- (if ent (release-ent! ent acctype))
- (set! tce-fct (+ tce-fct 1))
- (set! ent (find-prev-ent (get-ent (HAN-SEG han) (HAN-ID han) #f)
- LEAF -1 key-str k-len))
- (cond ((not ent) #f)
- ((eq? acctype ACCREAD) #f)
- ((ent-update-access ent ACCREAD acctype))
- (else (release-ent! ent ACCREAD)
- (set! ent #f)))
- ;;; (if ent (set! ent (prev-k-ent ent key-str k-len LEAF pkt)))
- ent)))
-
- ;(REL-BUK! seg blk-num)
- ;(fprintf diagout ">>>>ERROR<<<< all ents in use!\\n")
-
- (define (get-ent seg blk-num acctype)
- ; (fprintf diagout "get-ent %d:%ld %d\\n" seg blk-num acctype)
- (cond
- ((negative? blk-num)
- (fprintf diagout ">>>>ERROR<<<< negative block number %ld\\n" blk-num) #f)
- ((>= blk-num (SEG-USED seg))
- (fprintf diagout ">>>>ERROR<<<< bad block number %ld\\n" blk-num) #f)
- (else
- (let entloop ((ent (GET-BUK-WAIT seg blk-num)))
- (cond
- ((not ent) ;not here; get from disk
- (set! ent (try-get-free-ent seg blk-num))
- (cond
- (ent
- (ENT-SET-NEXT! ent (GET-BUK seg blk-num))
- (SET-BUK! seg blk-num ent)
- (ENT-SET-ACC! ent ACCPEND)
- (ENT-SET-SEG! ent seg)
- (ENT-SET-ID! ent blk-num)
- (ENT-SET-AGE! ent -127) ;not looked at till release-ent!
- (ENT-SET-DTY! ent #f)
- (ENT-SET-PUS! ent 0)
- (ENT-SET-REF! ent 1)
- (REL-BUK! seg blk-num)
- ;; (fprintf diagout "Reading block %d:%ld\\n" seg blk-num)
- (cond
- ((eq? acctype ACCWRITE)
- (ENT-SET-ACC! ent ACCWRITE)
- (ENT-SET-DTY! ent #t)
- (init-leaf-blk! (ENT-BLK ent) blk-num IND-TYP)
- (set! ge-ct (+ 1 ge-ct))
- ent)
- ((blk-read (SEG-PORT seg) (ENT-BLK ent) (SEG-BSIZ seg) blk-num)
- (ENT-SET-ACC! ent acctype) ;lines before here don't need to lck buk
- (if (not (= (BLK-ID (ENT-BLK ent)) blk-num))
- (fprintf diagout ">>>>ERROR<<<< corrupted blk %d:%ld <> %ld\\n"
- (ENT-SEG ent) blk-num (BLK-ID (ENT-BLK ent))))
- (set! ge-ct (+ 1 ge-ct))
- ent)
- (else ;read not successful; errmsg in blk-read
- (ENT-SET-REF! ent 0)
- (ENT-SET-ACC! ent #f)
- (set! ge-fct (+ 1 ge-fct))
- #f)))
- (else (entloop (GET-BUK-WAIT seg blk-num))))) ; try again
- ((not (and (= seg (ENT-SEG ent)) (= blk-num (ENT-ID ent)))) ;chain through buk
- (entloop (ENT-NEXT ent)))
- ((not (= (BLK-ID (ENT-BLK ent)) blk-num))
- (REL-BUK! seg blk-num)
- (fprintf diagout ">>>>ERROR<<<< corrupted buffer %d:%ld <> %ld\\n"
- (ENT-SEG ent) (BLK-ID (ENT-BLK ent)) blk-num)
- (set! ge-fct (+ 1 ge-fct))
- #f)
- ((not acctype) ; only asking NAME access
- (ENT-SET-REF! ent (+ 1 (ENT-REF ent)))
- (REL-BUK! seg blk-num)
- (set! ge-ct (+ 1 ge-ct))
- ent)
- ((not (ENT-ACC ent)) ; entry not lcked
- (ENT-SET-ACC! ent acctype)
- ;;; (if (eq? acctype ACCWRITE) (ENT-SET-DTY! ent #t))
- (ENT-SET-REF! ent (+ 1 (ENT-REF ent)))
- (REL-BUK! seg blk-num)
- (set! ge-ct (+ 1 ge-ct))
- ent)
- (else ; entry not available
- (REL-BUK! seg blk-num)
- (set! ge-fct (+ 1 ge-fct))
- #f))))))
-
- (define (switch-ent old-ent oldacc new-num newacc)
- ;;; (fprintf diagout "switch-ent %d:%ld %d %d %d\\n"
- ;;; (ENT-SEG old-ent) (ENT-ID old-ent) oldacc new-num newacc)
- (let ((new-ent (get-ent (ENT-SEG old-ent) new-num #f)))
- (release-ent! old-ent oldacc)
- (if new-ent (ent-update-access new-ent #f newacc)) ;doesn't check that access changed
- new-ent))
-
- ;;;minimum real NUM-ENTS-CT is 12*number of processes
- ;;;minimum NUM-BUKS IS 2, MAYBE 3 (due to how get-free-ent works)
- ;;;minimum real BLK-SIZE is 1.5K
-
- (define (init-wb MAX-NUM-ENTS-CT MAX-NUM-BUKS MAX-BLK-SIZE)
- (cond
- (free-ent-lck
- (fprintf diagout ">>>>ERROR<<<< init-wb: already initialized\\n")
- ARGERR)
- (else
- (set! diagout stdout)
- (fprintf diagout " Initializing %s.\\n" db-version-str)
- (fprintf diagout " Copyright (C) 1991, 1992, 1993 Holland Mark Martin.\\n")
- (fprintf diagout " See file README for terms applying to this program.\\n")
- (clear-stats)
- (set! num-buks MAX-NUM-BUKS)
- (set! blk-size MAX-BLK-SIZE)
- (set! empty-blk (make-string blk-size))
- (set! empty-blk-lck (make-lck -3))
- (set! free-buk-cntr 0)
- (set! free-ent-lck (make-lck -1))
- (set! flush-buk-cntr 0)
- (set! flush-buk-lck (make-lck -2))
- (set! buk-tab (make-vector num-buks #f))
- (set! lck-tab (make-vector num-buks #f))
- (set! ent-tab (make-vector ENT-TAB-INC #f))
- (do ((i num-buks (- i 1)))
- ((zero? i))
- (vector-set! lck-tab (- i 1) (make-lck (- i 1))))
- (do ((seg 9 (- seg 1)))
- ((negative? seg))
- (lck! (SEG-LCK seg))
- (SEG-SET-FLC! seg (make-vector FLC-LEN 0))
- (SEG-SET-FLC-LEN! seg 0)
- (unlck! (SEG-LCK seg)))
- (lck! free-ent-lck)
- (do ((i MAX-NUM-ENTS-CT (- i 1))
- (bent #f))
- ((zero? i) (set! free-ents bent))
- (let ((newent (make-ent num-ents-ct)))
- (cond (newent
- (ENT-SET-NEXT! newent bent)
- (set! bent newent)
- (vector-set! ent-tab num-ents-ct newent)
- (ENT-SET-TAG! newent num-ents-ct)
- (set! num-ents-ct (+ 1 num-ents-ct))
- (if (zero? (remainder num-ents-ct ENT-TAB-INC))
- (let ((tmp-ent-tab
- (vector-set-length! ent-tab
- (+ ENT-TAB-INC num-ents-ct))))
- (if tmp-ent-tab (set! ent-tab tmp-ent-tab)
- (set! i 1)))))
- (else ;no more memory - return
- (set! i 1)))))
- (unlck! free-ent-lck)
- num-ents-ct)))
-
- (define (final-wb)
- (cond (free-ent-lck ;make sure that init has happened.
- (do ((seg 9 (- seg 1)))
- ((negative? seg))
- (if (not (seg-free? seg)) (close-seg seg #t)))
- (lck! free-ent-lck)
- (do ((i num-ents-ct (- i 1)))
- ((zero? i))
- (free! (vector-ref ent-tab (+ -1 i)))
- (vector-set! ent-tab (+ -1 i) #f)
- (set! num-ents-ct (+ -1 num-ents-ct)))
- (unlck! free-ent-lck)
- (do ((seg 9 (- seg 1)))
- ((negative? seg))
- (lck! (SEG-LCK seg))
- (free! (SEG-FLC seg)) (SEG-SET-FLC! seg #f)
- (SEG-SET-FLC-LEN! seg 0)
- (unlck! (SEG-LCK seg)))
- (do ((i num-buks (- i 1)))
- ((zero? i))
- (free! (vector-ref lck-tab (- i 1)))
- (vector-set! lck-tab (- i 1) #f))
- (free! ent-tab) (set! ent-tab #f)
- (free! lck-tab) (set! lck-tab #f)
- (free! buk-tab) (set! buk-tab #f)
- (free! flush-buk-lck) (set! flush-buk-lck #f)
- (free! free-ent-lck) (set! free-ent-lck #f)
- (free! empty-blk) (set! empty-blk #f)
- (free! empty-blk-lck) (set! empty-blk-lck #f)
- SUCCESS)
- (else ARGERR)))
-
- (define (check-blk! blk)
- (let ((b-end (BLK-END blk)))
- (let lp ((b-pos BLK-DATA-START))
- (let ((s-pos (next-field blk (+ 1 b-pos))))
- (cond
- ((= s-pos b-end) #f)
- ((< s-pos b-end) (lp (next-cnvpair blk b-pos)))
- (else
- (fprintf diagout ">>>>ERROR<<<< check-blk!: blk %d past end %d\\n"
- (BLK-ID blk) s-pos)
- #f))))))
-
- (define (check-key-order! blk)
- (define split-str (make-string 256))
- (define spos (split-key-pos blk))
- (and spos (recon-this-key blk spos split-str 0 256)))
-
- (define (do-seg-buffers seg func)
- (let lp ((i num-buks) (ent #f)) ;was (ent free-ents)
- (cond ((not ent)
- (if (zero? i) SUCCESS
- (lp (- i 1) (vector-ref buk-tab (- i 1)))))
- ((or (negative? seg) (eq? seg (ENT-SEG ent)))
- (let ((ans (func ent)))
- (if (success? ans)
- (lp i (ENT-NEXT ent))
- ans)))
- (else (lp i (ENT-NEXT ent))))))
-
- (define (check-buffer ent)
- (cond ((not (zero? (ENT-REF ent)))
- ;(and (not (zero? (ENT-ID ent))))
- (fprintf diagout ">>>>ERROR<<<< Entry still referenced: %d:%ld\\n"
- (ENT-SEG ent) (ENT-ID ent))
- (ENT-SET-REF! ent 0)))
- (cond ((ENT-ACC ent)
- (fprintf diagout ">>>>ERROR<<<< Entry still lcked: %d:%ld\\n"
- (ENT-SEG ent) (ENT-ID ent))
- (ent-update-access ent (ENT-ACC ent) #f)))
- SUCCESS)
-
- (define (check-access!)
- (flush-some-buks 1 5) ;TBD remove when flush works on alarm int.
- (check-lcks)
- (do-seg-buffers -1 check-buffer))
-
- ;;; This routine needs to deal with lck issues.
- ;;; TBD needs to give error if lcked.
- (define (flush-buffer ent)
- (cond ((ENT-ACC ent) TERMINATED)
- ((ENT-DTY? ent) (if (ent-write ent) SUCCESS RETRYERR))
- (else SUCCESS)))
-
- (define (purge-buffer ent)
- (cond ((ENT-DTY? ent)
- (if (or (eq? (ENT-ACC ent) ACCWRITE)
- (eq? (ENT-ACC ent) ACCPEND))
- (fprintf diagout " Purging %s entry: %d:%ld\\n"
- (if (eq? (ENT-ACC ent) ACCWRITE) "ACCWRITE" "ACCPEND")
- (ENT-SEG ent) (ENT-ID ent)))
- (ent-write ent)))
- (amnesia-ent! ent)
- SUCCESS)
-